home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr05
/
xnot12a.zip
/
FILEIO.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-16
|
16KB
|
773 lines
#include "jam.h"
/*
* Name: Mg 2a
* MSDOS file I/O (TurboC 1.5)
*/
#include <stdlib.h>
#include <string.h>
#ifdef SomeUnix /* hack, really UNIX but .... */
# include "unistd.h"
#endif
#ifdef FAT /* DOS filesystem stuff */
# include <io.h>
# include <direct.h>
extern BOOL no_write_cr; /* JAM */
#endif
#include "def.h"
#include "keyname.h"
#include <stdio.h>
#include "kbd.h"
static FILE *ffp;
static BOOL doencrypt = FALSE;
static void rn_(evalEnv, (char *src, char *dest));
void setencryptstate(flag)
BOOL flag;
{
#ifdef DOCRYPT
doencrypt = flag;
#endif
}
/*
* Open a file for reading.
*/
ffropen(fn)
char *fn;
{
if ((ffp=fopen(fn, "rb")) == NULL)
return (FIOFNF);
return (FIOSUC);
}
/*
* Open a file for writing.
* Return TRUE if all is well, and
* FALSE on error (cannot create).
*/
ffwopen(fn)
char *fn;
{
if ((ffp=fopen(fn, "wb")) == NULL) {
ewprintf("Cannot open file for writing");
return (FIOERR);
}
return (FIOSUC);
}
/*
* Close a file.
* Should look at the status.
*/
ffclose()
{
(VOID) fclose(ffp);
return (FIOSUC);
}
/*
* Write a line to the already
* opened file. The "buf" points to the
* buffer, and the "nbuf" is its length, less
* the free newline. Return the status.
* Check only at the newline.
*/
ffputline(buf, nbuf)
register char buf[];
int nbuf;
{
register int i;
char c;
for (i=0; i<nbuf; ++i)
{
c = (char)(buf[i] & 0xFF);
#ifdef DOCRYPT
if (doencrypt)
docrypt(&c, 1);
#endif
putc(c, ffp);
}
#ifdef FAT
if (!no_write_cr)
putc('\r', ffp);
#endif
putc('\n', ffp);
if (ferror(ffp) != FALSE) {
ewprintf("Write I/O error");
return (FIOERR);
}
return (FIOSUC);
}
/*
* Write a buffer to the already
* opened file. bp points to the
* buffer. Return the status.
* Check only at the newline and
* end of buffer.
*/
ffputbuf(bp)
BUFFER *bp;
{
register char *cp;
char c;
register char *cpend;
register LINE *lp;
register LINE *lpend;
register int count;
lpend = bp->b_linep;
lp = lforw(lpend);
do {
extern BOOL clearLineChange;
if (clearLineChange)
changelineflag(lp, FALSE);
cp = <ext(lp)[0]; /* begining of line */
cpend = &cp[llength(lp)]; /* end of line */
count = 0;
while(cp != cpend) {
c = *cp++;
#ifdef DOCRYPT
if (doencrypt)
docrypt(&c, 1);
#endif
putc(c, ffp);
count++;
}
lp = lforw(lp);
if(lp == lpend) /* no implied newline on last line */
{
break;
}
#ifdef FAT
if (!no_write_cr)
putc('\r', ffp);
#endif
putc('\n', ffp);
} while(!ferror(ffp));
if(ferror(ffp)) {
ewprintf("Write I/O error");
return FIOERR;
}
return FIOSUC;
}
/*
* Read a line from a file, and store the bytes
* in the supplied buffer. Stop on end of file or end of
* line. Don't get upset by files that don't have an end of
* line on the last line; this seem to be common on CP/M-86 and
* MS-DOS. Delete any CR followed by a NL: This is the normal
* format for MS_DOS files, but also occurs when files are transferred
* from VMS or MS-DOS to Unix.
*/
ffgetline(buf, nbuf, nbytes)
register char buf[];
int nbuf;
register int *nbytes;
{
register int c;
register int i;
char cc;
i = 0;
for (;;) {
c = getc(ffp);
rescan:
if (c == '\r') { /* Delete any non-stray */
c = getc(ffp); /* carriage returns. */
if (c != '\n') {
buf[i++] = '\r';
if (i >= nbuf)
return FIOLONG;
goto rescan;
}
}
if (c==EOF || c==(char)'\n') /* End of line. */
break;
cc = (char)c;
#ifdef DOCRYPT
if (doencrypt)
docrypt(&cc, 1);
#endif
buf[i++] = (char)cc;
if (i >= nbuf)
return FIOLONG;
}
if (c == EOF && ferror(ffp) != FALSE) {
ewprintf("File read error");
return FIOERR;
}
*nbytes = i;
return c==EOF ? FIOEOF : FIOSUC;
}
/*
* Rename the file "fname" into a backup copy.
* On Unix the backup has the same name as the
* original file, with a "~" on the end - unfortunately
* this does not map well to MS-DOS - the old .bak convention
* is used.
*/
fbackupfile(fname)
char *fname;
{
register char *nname, *ptr;
char *strchr();
char *bak = ".bak";
/* copy the name, allocating enough space for
* backup extension and trailing NULL
*/
if ((nname=malloc(strlen(fname)+strlen(bak)+1)) == NULL)
return (ABORT);
(void) strcpy(nname, fname);
#ifdef FAT
if ((ptr = strchr(nname, '.')) != 0)
strcpy(ptr, bak);
else
#endif
strcat(nname, bak);
if (strcmp(fname, nname) == 0) {
free(nname);
return FALSE;
}
#ifdef FAT
(void) unlink(nname); /* Ignore errors. */
(void) rename(fname, nname);
#else /* unix land, cp to backup name to preserve softlinked 'originals' */
{
char *cmd;
static char *cpstr = "cp %s %s";
cmd = malloc(strlen(cpstr) + strlen(fname) + strlen(nname) + 10);
sprintf(cmd, cpstr, fname, nname);
system(cmd);
free(cmd);
}
#endif
free(nname);
return (TRUE);
}
/*
* The string "fn" is a file name.
* convert all filenames to lower case, and convert all '\\' characters
* to forward slashes. This is simply my preference, uppercase and
* back slashes are also viable.
*/
/*ARGSUSED*/
adjustnamecase(fn)
register char *fn;
{
#ifdef FAT /* only OS currently supported which doesn't care */
register char c;
while ((c = *fn) != '\0') {
if (ISUPPER(c))
*fn = (char)TOLOWER(c);
if (c=='/')
*fn = BDC1;
++fn;
}
#endif
return TRUE;
}
/*
* Check first in startup directory, then local work dir, then
* check env variable (order is probably wrong...)
*/
char *startupfile(path)
char *path;
{
register char *home = homedir;
static char name[NFILEN];
char thename[NFILEN];
register int i;
#define EXT ".st"
BOOL success = FALSE;
/* build start file name
*/
#ifdef WINDOWED
strcpy(thename, g_APPNAME);
#else
strcpy(thename, AppName);
#endif
strcat(thename, EXT);
for (i = 0; thename[i]; i++)
if (ISUPPER(thename[i]))
thename[i] = (char)TOLOWER(thename[i]);
/* file in home dir?
*/
if (!success && home && *home)
{
name[0] = '\0';
strcpy(name, home);
i = strlen(name);
if (i && (name[i-1] != BDC1))
name[i++] = BDC1;
name[i] = 0;
strcat(name, thename);
if (access(name, F_OK) == 0)
success = TRUE;
}
/* file in startup dir?
*/
if (!success && path)
{
strcpy(name, path);
strcat(name, thename);
if (access(name, F_OK) == 0)
success = TRUE;
}
/* file in current dir?
*/
if (!success && (access(thename, F_OK) == 0))
{
strcpy(name, thename);
success = TRUE;
}
if (success)
return (name);
return NULL;
}
/*******************************************************************/
/* new stuff between release 1a and 2a */
/*******************************************************************/
/* convert all filenames to a canonical format, which in the case of
* MSDOS is X:/currentdir/filename. Note that each drive letter has
* it's OWN current directory, so if the user specifies a drive letter,
* we use that drive's current directory, not it's root.
*/
/* MSC doesn't have getdrive and getcurdir routines; simulate them.
* They are both pretty gross. Blame Microsoft
*
* (code moved to dos.c - JAM)
*/
/* This DOS version of this code already does the right thing
* for constructing full pathnames from partial ones; I need to
* do special ughly stuff for UN*X systems, especially since I
* add incremental saves and path preloading... JAM
*
* Note that this code does not check for overflow!
*/
char *adjustname(fn)
register char *fn;
{
register char *cp;
#ifdef FAT
static char fnb[NFILEN * 2];
cp = fnb;
/* handle A:foo\bar */
if (fn[0] && fn[1] == ':') {
*cp++ = *fn++;
*cp++ = *fn++;
*cp = '\0';
adjustnamecase(fnb); /* force case to lower */
if (*fn != '/' && *fn != BDC1) {
*cp++ = BDC1;
getcurdir((unsigned short)(fnb[0]-'a'+1), cp);
cp = fnb + strlen(fnb);
}
else
*cp++ = *fn++;
}
/* handle \foo\bar */
else if (*fn == '/' || *fn == BDC1) {
*cp++ = (char) (getdisk() + 'a');
*cp++ = ':';
*cp++ = BDC1; fn++;
}
else {
strcpy(fnb, wdir);
cp = fnb + strlen(fnb);
}
if(cp != fnb && cp[-1] != '/' && cp[-1] != BDC1)
*cp++ = BDC1;
/* at this point, we should have a drive, and at least a single */
/* slash. Now copy over the rest of the filename, while handling */
/* certain pathalogical cases */
/* convert "//" to "/", "/./" to "/", and "/x/../" to "/" */
while(*fn) {
switch(*fn) {
case '.':
switch(fn[1]) {
case '\0':
*--cp = '\0';
adjustnamecase(fnb);
return fnb;
case BDC1:
fn += 2;
continue;
case '.':
if(fn[2]=='/' || fn[2]==BDC1 || fn[2] == '\0') {
--cp;
while(cp > fnb && *--cp != '/' && *cp != BDC1)
;
if (cp==fnb) cp += 2;
++cp;
if(fn[2]=='\0') {
*--cp = '\0';
adjustnamecase(fnb);
return fnb;
}
fn += 3;
continue;
}
break;
default:
break;
}
break;
case '/':
case BDC1:
fn++;
continue;
default:
break;
}
while(*fn && (*cp++ = *fn++) != '/' && fn[-1] != BDC1)
;
}
if (cp != fnb + 3 && cp[-1]==BDC1)
--cp;
*cp = '\0';
#else /* assuming UN*X here... */
static char fnb[NFILEN * 2];
if ((fn[0] == '~') && homedir && *homedir)
{
strcpy(fnb, homedir);
strcat(fnb, &fn[1]); /* assuming ~/foo so / already there */
}
else if (fn[0] == '$') /* env variable */
evalEnv(fn, fnb);
else if (fn[0] == BDC1) /* full path assumed! */
strcpy(fnb, fn);
else
{
BUFFER temp;
char buf[NFILEN];
int i;
memset(&temp, 0, sizeof(BUFFER));
strcpy(temp.b_fname, fn); /* use dir code to expand path */
if (switchdir(&temp)) /* if ok, use it else punt */
{
strcpy(fnb, dirpath());
i = strlen(fn) - 1;
while (i >= 0)
if (fn[i] == BDC1) /* end of name */
{
i++;
break;
}
else
i--;
if (i < 0)
i = 0;
strcat(fnb, &fn[i]);
}
else
strcpy(fnb, fn);
}
#endif /* FAT */
adjustnamecase(fnb);
return fnb;
}
/* I completely re-hacked this code; it used to
* spawn command.com to get the names. Now, it calls
* an OS specific function which is in dos.c or unix.c.
* Note that the unix version does a system call, but it's
* much cleaner that this was, portable and the dos
* version works on DOS, Windows, and NT! (JAM)
*/
BUFFER *dired_(dirname)
char *dirname;
{
register BUFFER *bp;
int i;
register char *s;
if((dirname = adjustname(dirname)) == NULL) {
ewprintf("Bad directory name");
return NULL;
}
adjustnamecase(dirname);
s = malloc(strlen(dirname) + 4);
strcpy(s, dirname);
i = strlen(s) - 1;
if (s[i] != BDC1)
{
i++;
s[i++] = BDC1;
s[i] = '\0';
}
if (!(bp = bfind(s, TRUE)))
{
ewprintf("Could not create buffer");
free(s);
return NULL;
}
if(bclear(bp) != TRUE)
{
free(s);
return FALSE;
}
GetDiskDirectory(bp, s);
bp->b_dotp = lforw(bp->b_linep); /* go to first line */
(VOID) strncpy(bp->b_fname, dirname, NFILEN);
if((bp->b_modes[0] = name_mode(DiredStr)) == NULL) {
bp->b_modes[0] = &map_table[0];
ewprintf(modeerr, DiredStr);
free(s);
return NULL;
}
bp->b_flag |= BFVIEW;
bp->b_flag &= ~BFREVERT;
bp->b_nmodes = 0;
free(s);
return bp;
}
/* This is special hack code to do my version of
* file name auto-complete. (JAM)
*/
int diredfiles_(f, n)
int f, n;
{
register BUFFER *bp;
char buffer[NFILEN * 4];
char bname[NFILEN], dspec[NFILEN * 4];
int i;
BOOL found = FALSE;
getcmdinput(buffer);
adjustnamecase(buffer);
#ifdef SomeUnix
{
char buf1[NFILEN * 4];
evalEnv(buffer, buf1);
strcpy(buffer, buf1);
}
#endif
strcpy(bname, buffer);
for (i = 0; i < (int)strlen(bname); i++)
if (bname[i] == '*')
{
found = TRUE;
break;
}
if (!found)
#ifdef SomeUnix
strcat(bname, "*");
#else
strcat(bname, "*.*");
#endif
strcpy(dspec, buffer);
/* fixup buffer now so is real dir name
*/
for (i = strlen(buffer)-1; i >= 0; i--)
{
if (buffer[i] == BDC1)
break;
buffer[i] = '\0';
}
/* make the buffer
*/
if (!(bp = bfind(bname, TRUE)))
{
ewprintf("Could not create buffer");
return FALSE;
}
if(bclear(bp) != TRUE)
return FALSE;
GetDiskDirectory(bp, dspec);
bp->b_dotp = lforw(bp->b_linep); /* go to first line */
(VOID) strncpy(bp->b_fname, buffer, NFILEN);
if((bp->b_modes[0] = name_mode(DiredStr)) == NULL) {
bp->b_modes[0] = &map_table[0];
ewprintf(modeerr, DiredStr);
return FALSE;
}
bp->b_nmodes = 0;
bp->b_flag |= BFVIEW;
return (popbuf(bp) ? TRUE : FALSE);
}
/* This is really ugly, but then so was the UNIX version!
*/
/* This version knows that the dir buffer was built
* via DOS/UN*X calls and word (foo.xxx) is the file name,
* ie it is better than before because at least now line formatting
* is controled OS-independent. - JAM
*/
d_makename(lp, fn)
LINE *lp;
char *fn;
{
register int i, j;
char c;
/* buffer name not useful for filename
* if not regular dir-built buffer
*/
if ((curbp->b_flag & BFREVERT) == 0)
{
(VOID) strcpy(fn, curbp->b_fname);
/* scrub the wildcard which may be here from diredfiles_
*/
for (i = 0; fn[i]; i++)
if (fn[i] == '*')
{
fn[i] = '\0'; /* should only be this one */
break;
}
}
else
fn[0] = '\0';
j = strlen(fn);
if (j > 0)
if (fn[j-1] != BDC1)
fn[j++] = BDC1;
/* find the word; if on space/tab, error and return\
* else backup to word and then copy till work end
*/
if (((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ') ||
( c == '\t'))
{
ewprintf("Cursor not on a filename.");
return(ABORT);
}
/* backup to whitespace
*/
for (i = curwp->w_doto; i >= 0; i--)
{
c = lgetc(lp, i);
if ((c == ' ') || (c == '\t'))
{
i++;
break;
}
}
if ( i < 0)
i = 0;
for (; i < llength(lp); i++, j++)
{
fn[j] = lgetc(lp, i);
if ((fn[j] == ' ') || (fn[j] == '\t'))
break;
}
fn[j] = '\0';
/*lowercase this
*/
adjustnamecase(fn);
return(0); /* DosGetDirectory returns NORMAL files only */
}
/* For some reason, this was a system call!
*/
#if 0
copy(frname, toname)
char *frname, *toname;
{
FILE *in, *out;
char c = ~EOF;
in = fopen(frname, "rb");
out = fopen(toname, "wb");
if (in && out)
{
for (;c != EOF;)
if ((c = (char)getc(in)) != EOF)
putc(c, out);
fclose(in);
fclose(out);
}
return TRUE;
}
#endif
BOOL fileisok(s)
char *s;
{
return(access(s, F_OK) == 0);
}
#ifdef SomeUnix /* someday I might make this work for DOS! */
static void evalEnv(s, d)
char *s, *d;
{
char envvar[NFILEN], *p;
int i;
/* To get here means s[0] == $ so expand it out and
* construct a useful name
*
* Collect env name up to standard delim (BDC1) or
* EOF on string
*/
for (i = 1; s[i] && (s[i] != BDC1); i++)
envvar[i-1] = s[i];
envvar[i-1] = 0;
p = (char *)getenv(envvar);
if (p && *p)
{
strcpy(d, p);
strcat(d, &s[i]);
}
else
strcpy(d, s); /* failure defaults to original */
}
#endif